package flychess.controller;

import flychess.data.GameMap;
import flychess.data.RandomGameMap;
import flychess.data.StaticGameMap;
import flychess.entity.*;
import flychess.rules.impl.*;
import flychess.util.UserInput;
import flychess.view.DisplayMap;
import flychess.view.DisplayMapAdvanced;
import flychess.view.DisplayMapInWindow;
import flychess.view.DisplayMapRect;

public class GameEngine {
    private GameMap map; // 地图数据
    private DisplayMap displayMap; // 展示游戏地图的对象
    private final Player[] players = new Player[2]; // 玩家数组，两个玩家，玩家分为普通玩家和电脑玩家
    /**
     * 初始化游戏的一局
     */
    public void init() {
        int sel, opt, opt2;
        System.out.println();
        System.out.println("--------------------请选择这局游戏的角色列表-----------------------");
        for (int i = 0; i < PlayerInfoOption.roleOptions.size(); i++) {
            System.out.print((i + 1) + ":   ");
            System.out.println(PlayerInfoOption.roleOptions.get(i));
        }
        sel = UserInput.getInputNum(1, PlayerInfoOption.roleOptions.size(), PlayerType.COMMON);
        PlayerInfoOption.roleSelected = PlayerInfoOption.roleOptions.get(sel - 1);
        GameDisplay.printOptions("游戏模式", new String[]{"人机对战", "双人对战"});
        sel = UserInput.getInputNum(1, 2, PlayerType.COMMON);
        GameDisplay.printOptions("游戏地图的关卡类型", new String[]{"固定关卡的地图", "随机关卡的地图"});
        opt = UserInput.getInputNum(1, 2, PlayerType.COMMON);
        GameDisplay.printOptions("地图显示方式", new String[]{"普通形状", "随机形状", "复杂形状", "GUI界面显示"});
        opt2 = UserInput.getInputNum(1, 4, PlayerType.COMMON);
        players[0] = new CommonPlayer();
        if (sel == 1) {
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~人  机  对  战~~~~~~~~~~~~~~~~~~~~~~~~\n");
            players[1] = new RobotPlayer();
        } else if (sel == 2){
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~双  人  对  战~~~~~~~~~~~~~~~~~~~~~~~~\n");
            players[1] = new CommonPlayer();
        }
        if (opt == 1) {
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~固  定  关  卡  地  图~~~~~~~~~~~~~~~~~~~~~~~~\n");
            map = new StaticGameMap(104);
        } else if (opt == 2) {
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~随  机  关  卡  地  图~~~~~~~~~~~~~~~~~~~~~~~~\n");
            map = new RandomGameMap(104);
        }
        map.createMap(); // 生成地图
        if (opt2 == 1) {
            displayMap = new DisplayMapRect(map, false);
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~普 通 形 状 的 地 图~~~~~~~~~~~~~~~~~~~~~~~~\n");
        } else if (opt2 == 2) {
            displayMap = new DisplayMapRect(map, true);
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~随 机 形 状 的 地 图~~~~~~~~~~~~~~~~~~~~~~~~\n");
        } else if (opt2 == 3) {
            displayMap = new DisplayMapAdvanced(map);
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~复 杂 形 状 的 地 图~~~~~~~~~~~~~~~~~~~~~~~~\n");
        } else if (opt2 == 4) {
            displayMap = new DisplayMapInWindow(map);
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~GUI 界 面 显 示 的 地 图~~~~~~~~~~~~~~~~~~~~~~~~\n");
        }
        // 设置玩家的起始位置、下一次走或停
        players[0].setPlayerInfo(0, "Ａ", "A", "on");
        players[1].setPlayerInfo(0, "Ｂ", "B","on");
        players[0].setPlayerID(PlayerInfoOption.playerIDs.get(0));
        players[1].setPlayerID(PlayerInfoOption.playerIDs.get(1));
        GameDisplay.printOptions("角色", PlayerInfoOption.roleSelected.toArray(new String[0]));
    }

    /**
     * 开始游戏
     */
    public void start() {
        GameDisplay.enterGame(); // 游戏初始界面
        init(); // 初始化
        // 通过键盘输入接收用户选择的角色，注意，不允许角色重复
        players[0].selectRole(players[1]); // 玩家1选择角色
        players[1].selectRole(players[0]); // 玩家2选择角色
        play(); // 开始对战
    }

    /**
     * 对战
     */
    public void play() {
        // 开始游戏
        GameDisplay.gameStart();
        // 显示对战双方士兵图标
        displayMap.showPlayerIcon(players[0], players[1]);
        // 显示对战地图
        displayMap.printIconInfo();
        displayMap.showMap(players[0], players[1]);
        System.out.println("\n");
        // 游戏开始
        // 有任何一方走到终点，跳出循环
        while (players[0].getPlayerPos() < map.mapLen - 1
                && players[1].getPlayerPos() < map.mapLen - 1) {
            // 轮流掷骰子
            gameTurn(players[0], players[1]); // 玩家1进行一轮
            if (players[0].getPlayerPos() >= map.mapLen - 1) break; // 玩家1获胜
            gameTurn(players[1], players[0]); // 玩家2进行下一轮
        }
        // 游戏结束
        GameDisplay.gameOver();
        judge();
    }
    /**
     * 玩家进行一轮游戏
     */
    public void gameTurn(Player player, Player rival) {
        if (player.getGoAndStop().equals("on")) {
            // 玩家no掷骰子
            updatePlayerPos(player, rival);
            // 显示对战地图
            displayMap.printIconInfo();
            displayMap.showMap(players[0], players[1]); // 显示当前地图
        } else {
            GameDisplay.pause(player);
            player.setGoAndStop("on"); // 设置下次可掷状态
        }
    }

    /**
     * 根据玩家掷的骰子数来更新玩家的位置
     * @param player 当前玩家
     * @param rival 对手
     */
    public void updatePlayerPos(Player player, Player rival) {
        int step = player.rollDice(); // 掷骰子
        // 计算这一次移动后的当前位置，并更新玩家在地图中的位置
        player.setPlayerPos(getCurPos(player, rival, player.getPlayerPos(), step));
        GameDisplay.rollDiceResult(player, rival, step);
    }

    /**
     * 计算玩家此次移动后的当前位置
     *
     * @param player 当前玩家
     * @param rival 对手
     * @param position
     *            移动前位置
     * @param step
     *            掷的骰子数目
     * @return position 移动后的位置
     */
    public int getCurPos(Player player, Player rival, int position, int step) {
        position = position + step; // 第一次移动后的位置
        position = map.convertToLegal(position);  // 到达终点
        // 根据地图中的关卡代号进行判断
        if (map.map[position] == DisplayMap.iconNameToIndex.get("normal"))
            position = new NormalRule().handleRule(player, rival, position);
        else if (map.map[position] == DisplayMap.iconNameToIndex.get("luckyTurn"))
            position = new LuckyTurnRule(map).handleRule(player, rival, position);
        else if (map.map[position] == DisplayMap.iconNameToIndex.get("landMine"))
            position = new LandMineRule().handleRule(player, rival, position);
        else if (map.map[position] == DisplayMap.iconNameToIndex.get("pause"))
            position = new PauseRule().handleRule(player, rival, position);
        else if (map.map[position] == DisplayMap.iconNameToIndex.get("timeTunnel"))
            position = new TimeTunnelRule().handleRule(player, rival, position);
        // 返回此次掷骰子后玩家的位置坐标
        return map.convertToLegal(position);
    }
    /**
     * 显示对战结果
     */
    public void judge() {
        if (players[0].getPlayerPos() > players[1].getPlayerPos()) {
            GameDisplay.printWinner(players[0]);
        } else {
            GameDisplay.printWinner(players[1]);
        }
    }
}